package de.ba_rm.java.password.checker.logic.config;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.util.Arrays;

import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang3.StringUtils;

import de.ba_rm.java.password.checker.Messages;

/**
 * 
 * @author sebastian.toense@gmail.com
 *
 */
public class RuleIO {
	
	private static final String PARENT_FOLDER_NAME = "configs";
	
	public static final String XML = ".xml";
	
	private RuleIO() {}
	
	/**
	 * 
	 * @return
	 */
	private static boolean createParentDirIfNotExists() {
		final File config = new File(PARENT_FOLDER_NAME);
		if (!config.exists()) {
			return config.mkdir();
		} else if (!config.isDirectory()) {
			return config.delete() && config.mkdir();
		} else {
			return true;
		}
	}
	
	/**
	 * 
	 * @return
	 * @throws JAXBException
	 */
	private static Marshaller createMarshaller() throws JAXBException {
		final JAXBContext context = JAXBContext.newInstance(Rule.class);
		final Marshaller marshaller = context.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		return marshaller;
	}
	
	/**
	 * 
	 * @param rule
	 * @return
	 * @throws JAXBException
	 * @throws FileNotFoundException 
	 */
	public static boolean save(final Rule rule) throws JAXBException, FileNotFoundException {
		if (createParentDirIfNotExists()) {
			createMarshaller().marshal(rule, fileFromName(rule.getName()));
		}
		return true;
	}

	/**
	 * 
	 * @param name
	 * @return
	 * @throws FileNotFoundException
	 */
	public static boolean nameAlreadyExists(final String name) throws FileNotFoundException {
		final String[] fileNames = loadRulesetNames();
		return CollectionUtils.exists(Arrays.asList(fileNames), new Predicate() {
			@Override
			public boolean evaluate(Object object) {
				return ((String) object).equalsIgnoreCase(StringUtils.trimToEmpty(name) + XML);
			}
		});
	}

	/**
	 * 
	 * @param fileName
	 * @return
	 */
	public static File fileFromName(final String fileName) {
		final StringBuilder builder = new StringBuilder();
		builder.append(PARENT_FOLDER_NAME);
		builder.append(File.separator);
		builder.append(fileName);
		builder.append(XML);
		return new File(builder.toString());
	}
	
	/**
	 * 
	 * @param file
	 * @return
	 */
	public static Rule load(final File file) {
		return JAXB.unmarshal(file, Rule.class);
	}
	
	public static Rule load(final String string) {
		final File file = fileFromName(string);
		return JAXB.unmarshal(file, Rule.class);
	}

	public static File[] loadRulesets() throws FileNotFoundException {
		if (createParentDirIfNotExists()) {
			return new File(PARENT_FOLDER_NAME).listFiles(new XmlFilter());
		} else {
			throw new FileNotFoundException(Messages.getString("Exception.0", PARENT_FOLDER_NAME));
		}
	}
	
	public static String[] loadRulesetNames() throws FileNotFoundException {
		if (createParentDirIfNotExists()) {
			return new File(PARENT_FOLDER_NAME).list(new XmlFilter());
		} else {
			throw new FileNotFoundException(Messages.getString("Exception.0", PARENT_FOLDER_NAME));
		}
	}
	
	private static final class XmlFilter implements FilenameFilter {

		@Override
		public boolean accept(File dir, String name) {
			return name.endsWith(XML);
		}
		
	}
}
